using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Formatter;
using System.Text;
using System.Text.Json;
using Uantek.Device.Communication.Models;
using Uantek.Device.Communication.Services.Interfaces;

namespace Uantek.Device.Communication.Services
{
    /// <summary>
    /// MQTT发布服务实现
    /// </summary>
    public class MqttPublishService : IMqttPublishService, IDisposable
    {
        private readonly ILogger<MqttPublishService> _logger;
        private IManagedMqttClient? _mqttClient;
        private string _defaultTopicPrefix = "factory";
        private bool _disposed = false;

        public MqttPublishService(ILogger<MqttPublishService> logger)
        {
            _logger = logger;
        }

        public bool IsConnected => _mqttClient?.IsConnected ?? false;

        public event EventHandler<bool>? ConnectionStatusChanged;
        public event EventHandler<(string Topic, bool Success)>? MessagePublished;

        public async Task<CommunicationResult> ConnectAsync(string serverAddress, int port, string clientId, string? username = null, string? password = null)
        {
            try
            {
                if (_mqttClient != null && _mqttClient.IsConnected)
                {
                    return new CommunicationResult { Success = false, Message = "MQTT客户端已连接" };
                }

                var factory = new MqttFactory();
                _mqttClient = factory.CreateManagedMqttClient();

                // 配置连接选项
                var clientOptionsBuilder = new MqttClientOptionsBuilder()
                    .WithTcpServer(serverAddress, port)
                    .WithClientId(clientId)
                    .WithProtocolVersion(MqttProtocolVersion.V311)
                    .WithCleanSession(true);

                if (!string.IsNullOrEmpty(username))
                {
                    clientOptionsBuilder.WithCredentials(username, password);
                }

                var managedOptions = new ManagedMqttClientOptionsBuilder()
                    .WithClientOptions(clientOptionsBuilder.Build())
                    .WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
                    .Build();

                // 订阅事件
                _mqttClient.ConnectedAsync += OnConnectedAsync;
                _mqttClient.DisconnectedAsync += OnDisconnectedAsync;
                _mqttClient.ConnectingFailedAsync += OnConnectingFailedAsync;

                await _mqttClient.StartAsync(managedOptions);

                // 等待连接建立
                var timeout = TimeSpan.FromSeconds(10);
                var startTime = DateTime.Now;
                while (!_mqttClient.IsConnected && DateTime.Now - startTime < timeout)
                {
                    await Task.Delay(100);
                }

                if (_mqttClient.IsConnected)
                {
                    _logger.LogInformation($"MQTT客户端连接成功: {serverAddress}:{port}");
                    return new CommunicationResult { Success = true, Message = "MQTT连接成功" };
                }
                else
                {
                    return new CommunicationResult { Success = false, Message = "MQTT连接超时" };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"MQTT连接失败: {serverAddress}:{port}");
                return new CommunicationResult { Success = false, Message = $"MQTT连接失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> DisconnectAsync()
        {
            try
            {
                if (_mqttClient != null)
                {
                    await _mqttClient.StopAsync();
                    _mqttClient.ConnectedAsync -= OnConnectedAsync;
                    _mqttClient.DisconnectedAsync -= OnDisconnectedAsync;
                    _mqttClient.ConnectingFailedAsync -= OnConnectingFailedAsync;
                    _mqttClient.Dispose();
                    _mqttClient = null;
                }

                _logger.LogInformation("MQTT客户端断开连接成功");
                return new CommunicationResult { Success = true, Message = "MQTT断开连接成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MQTT断开连接失败");
                return new CommunicationResult { Success = false, Message = $"MQTT断开连接失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> PublishDeviceDataAsync(DeviceDataModel deviceData, string? topic = null)
        {
            try
            {
                if (_mqttClient == null || !_mqttClient.IsConnected)
                {
                    return new CommunicationResult { Success = false, Message = "MQTT客户端未连接" };
                }

                // 生成主题：factory/{line}/{equipment}/{parameter}
                var actualTopic = topic ?? GenerateDeviceDataTopic(deviceData);
                var payload = JsonSerializer.Serialize(deviceData, new JsonSerializerOptions 
                { 
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase 
                });

                var message = new MqttApplicationMessageBuilder()
                    .WithTopic(actualTopic)
                    .WithPayload(payload)
                    .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                    .WithRetainFlag(false)
                    .Build();

                await _mqttClient.EnqueueAsync(message);

                _logger.LogDebug($"设备数据发布成功: {actualTopic}");
                MessagePublished?.Invoke(this, (actualTopic, true));
                return new CommunicationResult { Success = true, Message = "设备数据发布成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"发布设备数据失败: {deviceData.DeviceId}");
                MessagePublished?.Invoke(this, (topic ?? "unknown", false));
                return new CommunicationResult { Success = false, Message = $"发布设备数据失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> PublishDeviceStatusAsync(DeviceStatus deviceStatus, string? topic = null)
        {
            try
            {
                if (_mqttClient == null || !_mqttClient.IsConnected)
                {
                    return new CommunicationResult { Success = false, Message = "MQTT客户端未连接" };
                }

                var actualTopic = topic ?? $"{_defaultTopicPrefix}/status/{deviceStatus.DeviceId}";
                var payload = JsonSerializer.Serialize(deviceStatus, new JsonSerializerOptions 
                { 
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase 
                });

                var message = new MqttApplicationMessageBuilder()
                    .WithTopic(actualTopic)
                    .WithPayload(payload)
                    .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                    .WithRetainFlag(true) // 设备状态保持消息
                    .Build();

                await _mqttClient.EnqueueAsync(message);

                _logger.LogDebug($"设备状态发布成功: {actualTopic}");
                MessagePublished?.Invoke(this, (actualTopic, true));
                return new CommunicationResult { Success = true, Message = "设备状态发布成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"发布设备状态失败: {deviceStatus.DeviceId}");
                MessagePublished?.Invoke(this, (topic ?? "unknown", false));
                return new CommunicationResult { Success = false, Message = $"发布设备状态失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> PublishMessageAsync(string topic, string payload, bool retain = false)
        {
            try
            {
                if (_mqttClient == null || !_mqttClient.IsConnected)
                {
                    return new CommunicationResult { Success = false, Message = "MQTT客户端未连接" };
                }

                var message = new MqttApplicationMessageBuilder()
                    .WithTopic(topic)
                    .WithPayload(payload)
                    .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                    .WithRetainFlag(retain)
                    .Build();

                await _mqttClient.EnqueueAsync(message);

                _logger.LogDebug($"自定义消息发布成功: {topic}");
                MessagePublished?.Invoke(this, (topic, true));
                return new CommunicationResult { Success = true, Message = "自定义消息发布成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"发布自定义消息失败: {topic}");
                MessagePublished?.Invoke(this, (topic, false));
                return new CommunicationResult { Success = false, Message = $"发布自定义消息失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> PublishBatchDeviceDataAsync(IEnumerable<DeviceDataModel> deviceDataList)
        {
            try
            {
                if (_mqttClient == null || !_mqttClient.IsConnected)
                {
                    return new CommunicationResult { Success = false, Message = "MQTT客户端未连接" };
                }

                var messages = new List<MqttApplicationMessage>();
                var successCount = 0;
                var failCount = 0;

                foreach (var deviceData in deviceDataList)
                {
                    try
                    {
                        var topic = GenerateDeviceDataTopic(deviceData);
                        var payload = JsonSerializer.Serialize(deviceData, new JsonSerializerOptions 
                        { 
                            PropertyNamingPolicy = JsonNamingPolicy.CamelCase 
                        });

                        var message = new MqttApplicationMessageBuilder()
                            .WithTopic(topic)
                            .WithPayload(payload)
                            .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                            .WithRetainFlag(false)
                            .Build();

                        messages.Add(message);
                        successCount++;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"准备设备数据消息失败: {deviceData.DeviceId}");
                        failCount++;
                    }
                }

                // 批量发送消息
                foreach (var message in messages)
                {
                    await _mqttClient.EnqueueAsync(message);
                }

                var resultMessage = $"批量发布完成，成功: {successCount}，失败: {failCount}";
                _logger.LogInformation(resultMessage);
                return new CommunicationResult { Success = true, Message = resultMessage };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量发布设备数据失败");
                return new CommunicationResult { Success = false, Message = $"批量发布设备数据失败: {ex.Message}" };
            }
        }

        public void SetDefaultTopicPrefix(string topicPrefix)
        {
            _defaultTopicPrefix = topicPrefix ?? "factory";
            _logger.LogInformation($"默认主题前缀设置为: {_defaultTopicPrefix}");
        }

        public string GetDefaultTopicPrefix()
        {
            return _defaultTopicPrefix;
        }

        private string GenerateDeviceDataTopic(DeviceDataModel deviceData)
        {
            // 主题格式：factory/{line}/{equipment}/{parameter}
            var line = deviceData.ExtendedProperties.TryGetValue("line", out var lineValue) ? lineValue?.ToString() : "default";
            var equipment = deviceData.DeviceName ?? deviceData.DeviceId;
            
            // 为每个数据值生成独立的主题
            if (deviceData.DataValues.Count == 1)
            {
                var parameter = deviceData.DataValues.Keys.First();
                return $"{_defaultTopicPrefix}/{line}/{equipment}/{parameter}";
            }
            else
            {
                // 多个参数时使用通用主题
                return $"{_defaultTopicPrefix}/{line}/{equipment}/data";
            }
        }

        private async Task OnConnectedAsync(MqttClientConnectedEventArgs e)
        {
            _logger.LogInformation("MQTT客户端已连接");
            ConnectionStatusChanged?.Invoke(this, true);
            await Task.CompletedTask;
        }

        private async Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs e)
        {
            _logger.LogWarning($"MQTT客户端已断开连接: {e.Reason}");
            ConnectionStatusChanged?.Invoke(this, false);
            await Task.CompletedTask;
        }

        private async Task OnConnectingFailedAsync(ConnectingFailedEventArgs e)
        {
            _logger.LogError(e.Exception, "MQTT连接失败");
            await Task.CompletedTask;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                try
                {
                    _mqttClient?.StopAsync().Wait(TimeSpan.FromSeconds(5));
                    _mqttClient?.Dispose();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "释放MQTT客户端资源失败");
                }
                _disposed = true;
            }
        }

        ~MqttPublishService()
        {
            Dispose(false);
        }
    }
}